﻿
using Boilen.Primitives.Members;
using System.Collections.Generic;


namespace Boilen.Primitives.Implementers {

    /// <summary>
    /// Implements string constants for property names.
    /// </summary>
    public sealed class PropertyNameConstants : Implementer<string> {

        /// <summary>The suffix used for property name constants.</summary>
        public const string PropertyNameSuffix = "PropertyName";


        /// <inheritdoc/>
        protected override bool EnsureDescription { get { return false; } }


        /// <inheritdoc/>
        public PropertyNameConstants( PartialType parent )
            : base( parent, "PropertyNameConstants", PropertyNameSuffix ) { }


        /// <inheritdoc/>
        public override void Prepare( ) {
            base.Prepare( );
            this.PrepareTargets( ( ITarget t ) => t.Prepare( this ) );
        }


        /// <inheritdoc/>
        protected override IEnumerable<Member> GetMembers( ) {
            var group = new MemberGroup( "Property Names" ) { Condition = this.Condition };

            var namedProperties = this.GetTargetData( ( ITarget t ) => t.ShouldCreateConstant, ( ITarget t ) => new { t.PropertyName, t.Accessibility } );
            foreach( var namedProperty in namedProperties )
                group.Members.Add( this.CreateConstant( namedProperty.PropertyName, namedProperty.Accessibility ) );

            yield return group;
        }


        private ConstantMember CreateConstant( string propertyName, string accessibility ) {
            var constant = new ConstantMember( propertyName + PropertyNameSuffix, this.TypeName, '"' + propertyName + '"' ) {
                Modifiers = accessibility + " const",
                Doc = this.CreateDoc( )
                    .AddSummary( "The name of the %see:parent_type.{0}% property.", propertyName )
            };

            if( this.Parent.Type.IsGenericType )
                constant.Attributes.Add( AttributeMember.SuppressStaticMembersInGenericTypes );

            return constant;
        }


        /// <summary>
        /// Represents an <see cref="IImplementer"/> that supports the <see cref="PropertyNameConstants"/> construct.
        /// </summary>
        public interface ITarget : IImplementer {
            /// <summary>
            /// Gets a value indicating whether the property needs a constant property name value.
            /// </summary>
            bool ShouldCreateConstant { get; }

            /// <summary>
            /// Gets the name of the property represented by the target.
            /// </summary>
            string PropertyName { get; }

            /// <summary>
            /// Gets the accessibility of the property represented by the target.
            /// </summary>
            string Accessibility { get; }

            /// <summary>
            /// Called by <see cref="PropertyNameConstants"/> to prepare a target implementer.
            /// </summary>
            void Prepare( PropertyNameConstants implementer );
        }

    }

}
